"""
人流密度分析引擎
实现基于检测结果的密度计算、多区域统计、趋势预测和异常检测
"""
import asyncio
import logging
import numpy as np
from datetime import datetime, timedelta
from typing import List, Dict, Optional, Tuple, Any
from uuid import uuid4
from collections import defaultdict, deque
from dataclasses import dataclass, field
from enum import Enum
import json

from schemas.person_detection import PersonDetectionResult, PersonInfo
from schemas.ai_algorithm import BehaviorAnalysisResult, BehaviorType, AlertLevel
from core.config import get_settings

logger = logging.getLogger(__name__)
settings = get_settings()


class DensityLevel(str, Enum):
    """密度级别枚举"""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class TrendDirection(str, Enum):
    """趋势方向枚举"""
    INCREASING = "increasing"
    DECREASING = "decreasing"
    STABLE = "stable"
    FLUCTUATING = "fluctuating"


@dataclass
class Zone:
    """区域定义"""
    zone_id: str
    zone_name: str
    coordinates: List[Tuple[float, float]]  # 多边形顶点坐标
    max_capacity: int = 100
    warning_threshold: float = 0.7  # 70%容量时告警
    critical_threshold: float = 0.9  # 90%容量时严重告警
    
    def contains_point(self, x: float, y: float) -> bool:
        """判断点是否在区域内（射线法）"""
        n = len(self.coordinates)
        inside = False
        
        p1x, p1y = self.coordinates[0]
        for i in range(1, n + 1):
            p2x, p2y = self.coordinates[i % n]
            if y > min(p1y, p2y):
                if y <= max(p1y, p2y):
                    if x <= max(p1x, p2x):
                        if p1y != p2y:
                            xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x
                        if p1x == p2x or x <= xinters:
                            inside = not inside
            p1x, p1y = p2x, p2y
        
        return inside
    
    def get_area(self) -> float:
        """计算区域面积（鞋带公式）"""
        n = len(self.coordinates)
        area = 0.0
        for i in range(n):
            j = (i + 1) % n
            area += self.coordinates[i][0] * self.coordinates[j][1]
            area -= self.coordinates[j][0] * self.coordinates[i][1]
        return abs(area) / 2.0


@dataclass
class DensityMeasurement:
    """密度测量结果"""
    measurement_id: str
    camera_id: str
    zone_id: Optional[str]
    timestamp: datetime
    person_count: int
    density_value: float  # 人员/平方米
    density_level: DensityLevel
    area_coverage: float  # 区域覆盖率
    average_person_size: float
    hotspots: List[Dict[str, Any]]
    metadata: Dict[str, Any] = field(default_factory=dict)


@dataclass
class DensityTrend:
    """密度趋势"""
    trend_id: str
    camera_id: str
    zone_id: Optional[str]
    start_time: datetime
    end_time: datetime
    trend_direction: TrendDirection
    change_rate: float  # 变化率（人员/分钟）
    peak_density: float
    peak_time: datetime
    average_density: float
    confidence: float
    predictions: List[Dict[str, Any]] = field(default_factory=list)


@dataclass
class DensityAnomaly:
    """密度异常"""
    anomaly_id: str
    camera_id: str
    zone_id: Optional[str]
    timestamp: datetime
    anomaly_type: str  # sudden_increase, sudden_decrease, overcrowding, empty
    severity: AlertLevel
    description: str
    baseline_density: float
    current_density: float
    deviation_score: float
    duration: Optional[float] = None


class HeatmapGenerator:
    """热力图生成器"""
    
    def __init__(self, grid_size: int = 20):
        self.grid_size = grid_size
    
    def generate_heatmap(
        self, 
        persons: List[PersonInfo], 
        image_size: Tuple[int, int],
        zones: Optional[List[Zone]] = None
    ) -> Dict[str, Any]:
        """生成热力图数据"""
        width, height = image_size
        
        # 创建网格
        grid_width = width // self.grid_size
        grid_height = height // self.grid_size
        
        # 初始化热力图矩阵
        heatmap = np.zeros((grid_height, grid_width))
        
        # 统计每个网格的人员数量
        for person in persons:
            center_x = (person.bbox.x1 + person.bbox.x2) / 2
            center_y = (person.bbox.y1 + person.bbox.y2) / 2
            
            grid_x = int(center_x // self.grid_size)
            grid_y = int(center_y // self.grid_size)
            
            if 0 <= grid_x < grid_width and 0 <= grid_y < grid_height:
                heatmap[grid_y, grid_x] += 1
        
        # 应用高斯平滑
        from scipy import ndimage
        heatmap_smooth = ndimage.gaussian_filter(heatmap, sigma=1.0)
        
        # 归一化到0-1范围
        if heatmap_smooth.max() > 0:
            heatmap_normalized = heatmap_smooth / heatmap_smooth.max()
        else:
            heatmap_normalized = heatmap_smooth
        
        # 查找热点
        hotspots = self._find_hotspots(heatmap_normalized, threshold=0.5)
        
        # 按区域统计
        zone_stats = {}
        if zones:
            for zone in zones:
                zone_count = self._count_persons_in_zone(persons, zone)
                zone_density = zone_count / zone.get_area() if zone.get_area() > 0 else 0
                
                zone_stats[zone.zone_id] = {
                    'person_count': zone_count,
                    'density': zone_density,
                    'capacity_usage': zone_count / zone.max_capacity,
                    'status': self._get_zone_status(zone_count, zone)
                }
        
        return {
            'heatmap': heatmap_normalized.tolist(),
            'grid_size': self.grid_size,
            'image_size': image_size,
            'total_persons': len(persons),
            'hotspots': hotspots,
            'zone_statistics': zone_stats,
            'timestamp': datetime.now().isoformat()
        }
    
    def _find_hotspots(self, heatmap: np.ndarray, threshold: float = 0.5) -> List[Dict[str, Any]]:
        """查找热点区域"""
        hotspots = []
        height, width = heatmap.shape
        
        # 查找超过阈值的区域
        hot_points = np.where(heatmap >= threshold)
        
        if len(hot_points[0]) == 0:
            return hotspots
        
        # 聚类相邻的热点
        from sklearn.cluster import DBSCAN
        
        points = np.column_stack((hot_points[1], hot_points[0]))  # (x, y)
        clustering = DBSCAN(eps=2, min_samples=2).fit(points)
        
        for cluster_id in set(clustering.labels_):
            if cluster_id == -1:  # 噪声点
                continue
            
            cluster_points = points[clustering.labels_ == cluster_id]
            
            # 计算热点区域的边界框
            min_x, min_y = cluster_points.min(axis=0)
            max_x, max_y = cluster_points.max(axis=0)
            
            # 计算热点强度
            intensity = heatmap[min_y:max_y+1, min_x:max_x+1].mean()
            
            hotspot = {
                'hotspot_id': f"hotspot_{cluster_id}",
                'bbox': {
                    'x': int(min_x * self.grid_size),
                    'y': int(min_y * self.grid_size),
                    'width': int((max_x - min_x + 1) * self.grid_size),
                    'height': int((max_y - min_y + 1) * self.grid_size)
                },
                'intensity': float(intensity),
                'point_count': len(cluster_points)
            }
            
            hotspots.append(hotspot)
        
        return hotspots
    
    def _count_persons_in_zone(self, persons: List[PersonInfo], zone: Zone) -> int:
        """统计区域内的人员数量"""
        count = 0
        for person in persons:
            center_x = (person.bbox.x1 + person.bbox.x2) / 2
            center_y = (person.bbox.y1 + person.bbox.y2) / 2
            
            if zone.contains_point(center_x, center_y):
                count += 1
        
        return count
    
    def _get_zone_status(self, person_count: int, zone: Zone) -> str:
        """获取区域状态"""
        usage_rate = person_count / zone.max_capacity
        
        if usage_rate >= zone.critical_threshold:
            return "critical"
        elif usage_rate >= zone.warning_threshold:
            return "warning"
        elif usage_rate > 0.3:
            return "normal"
        else:
            return "low"


class TrendAnalyzer:
    """趋势分析器"""
    
    def __init__(self, window_size: int = 60):
        self.window_size = window_size  # 分析窗口大小（分钟）
        self.min_data_points = 10  # 最少数据点数量
    
    def analyze_trend(
        self, 
        measurements: List[DensityMeasurement],
        prediction_horizon: int = 30  # 预测时间范围（分钟）
    ) -> Optional[DensityTrend]:
        """分析密度趋势"""
        if len(measurements) < self.min_data_points:
            return None
        
        # 按时间排序
        measurements.sort(key=lambda x: x.timestamp)
        
        # 提取时间序列数据
        timestamps = [m.timestamp for m in measurements]
        densities = [m.density_value for m in measurements]
        
        # 计算趋势方向
        trend_direction = self._calculate_trend_direction(densities)
        
        # 计算变化率
        change_rate = self._calculate_change_rate(timestamps, densities)
        
        # 查找峰值
        peak_density, peak_time = self._find_peak(measurements)
        
        # 计算平均密度
        average_density = np.mean(densities)
        
        # 计算置信度
        confidence = self._calculate_confidence(densities)
        
        # 生成预测
        predictions = self._generate_predictions(
            timestamps, densities, prediction_horizon
        )
        
        trend = DensityTrend(
            trend_id=str(uuid4()),
            camera_id=measurements[0].camera_id,
            zone_id=measurements[0].zone_id,
            start_time=timestamps[0],
            end_time=timestamps[-1],
            trend_direction=trend_direction,
            change_rate=change_rate,
            peak_density=peak_density,
            peak_time=peak_time,
            average_density=average_density,
            confidence=confidence,
            predictions=predictions
        )
        
        return trend
    
    def _calculate_trend_direction(self, densities: List[float]) -> TrendDirection:
        """计算趋势方向"""
        if len(densities) < 3:
            return TrendDirection.STABLE
        
        # 使用线性回归计算趋势
        x = np.arange(len(densities))
        y = np.array(densities)
        
        # 计算斜率
        slope = np.polyfit(x, y, 1)[0]
        
        # 计算变异系数
        cv = np.std(densities) / np.mean(densities) if np.mean(densities) > 0 else 0
        
        if cv > 0.3:  # 变异系数大于30%认为是波动
            return TrendDirection.FLUCTUATING
        elif slope > 0.1:
            return TrendDirection.INCREASING
        elif slope < -0.1:
            return TrendDirection.DECREASING
        else:
            return TrendDirection.STABLE
    
    def _calculate_change_rate(self, timestamps: List[datetime], densities: List[float]) -> float:
        """计算变化率（人员/分钟）"""
        if len(timestamps) < 2:
            return 0.0
        
        total_time = (timestamps[-1] - timestamps[0]).total_seconds() / 60  # 转换为分钟
        total_change = densities[-1] - densities[0]
        
        return total_change / total_time if total_time > 0 else 0.0
    
    def _find_peak(self, measurements: List[DensityMeasurement]) -> Tuple[float, datetime]:
        """查找峰值"""
        max_measurement = max(measurements, key=lambda x: x.density_value)
        return max_measurement.density_value, max_measurement.timestamp
    
    def _calculate_confidence(self, densities: List[float]) -> float:
        """计算置信度"""
        if len(densities) < 3:
            return 0.5
        
        # 基于数据的一致性计算置信度
        std_dev = np.std(densities)
        mean_val = np.mean(densities)
        
        # 变异系数越小，置信度越高
        cv = std_dev / mean_val if mean_val > 0 else 1.0
        confidence = max(0.1, min(1.0, 1.0 - cv))
        
        return confidence
    
    def _generate_predictions(
        self, 
        timestamps: List[datetime], 
        densities: List[float],
        horizon: int
    ) -> List[Dict[str, Any]]:
        """生成预测"""
        predictions = []
        
        if len(densities) < 3:
            return predictions
        
        # 使用简单的线性外推
        x = np.arange(len(densities))
        y = np.array(densities)
        
        # 拟合线性模型
        coeffs = np.polyfit(x, y, 1)
        
        # 生成未来时间点的预测
        last_time = timestamps[-1]
        for i in range(1, horizon + 1):
            future_time = last_time + timedelta(minutes=i)
            predicted_density = coeffs[0] * (len(densities) + i - 1) + coeffs[1]
            
            # 确保预测值不为负
            predicted_density = max(0, predicted_density)
            
            prediction = {
                'timestamp': future_time.isoformat(),
                'predicted_density': predicted_density,
                'confidence': max(0.1, 1.0 - i * 0.02)  # 置信度随时间递减
            }
            
            predictions.append(prediction)
        
        return predictions


class AnomalyDetector:
    """异常检测器"""
    
    def __init__(self):
        self.baseline_window = 60  # 基线计算窗口（分钟）
        self.anomaly_threshold = 2.0  # 异常阈值（标准差倍数）
        self.sudden_change_threshold = 0.5  # 突变阈值
    
    def detect_anomalies(
        self, 
        current_measurement: DensityMeasurement,
        historical_measurements: List[DensityMeasurement]
    ) -> List[DensityAnomaly]:
        """检测异常"""
        anomalies = []
        
        if len(historical_measurements) < 10:
            return anomalies
        
        # 计算基线统计
        baseline_densities = [m.density_value for m in historical_measurements[-self.baseline_window:]]
        baseline_mean = np.mean(baseline_densities)
        baseline_std = np.std(baseline_densities)
        
        current_density = current_measurement.density_value
        
        # 计算偏差分数
        deviation_score = abs(current_density - baseline_mean) / baseline_std if baseline_std > 0 else 0
        
        # 检测统计异常
        if deviation_score > self.anomaly_threshold:
            anomaly_type = "sudden_increase" if current_density > baseline_mean else "sudden_decrease"
            severity = AlertLevel.HIGH if deviation_score > 3.0 else AlertLevel.MEDIUM
            
            anomaly = DensityAnomaly(
                anomaly_id=str(uuid4()),
                camera_id=current_measurement.camera_id,
                zone_id=current_measurement.zone_id,
                timestamp=current_measurement.timestamp,
                anomaly_type=anomaly_type,
                severity=severity,
                description=f"检测到密度异常变化：当前{current_density:.2f}，基线{baseline_mean:.2f}",
                baseline_density=baseline_mean,
                current_density=current_density,
                deviation_score=deviation_score
            )
            
            anomalies.append(anomaly)
        
        # 检测过度拥挤
        if current_measurement.density_level == DensityLevel.CRITICAL:
            anomaly = DensityAnomaly(
                anomaly_id=str(uuid4()),
                camera_id=current_measurement.camera_id,
                zone_id=current_measurement.zone_id,
                timestamp=current_measurement.timestamp,
                anomaly_type="overcrowding",
                severity=AlertLevel.CRITICAL,
                description=f"检测到严重拥挤：密度{current_density:.2f}",
                baseline_density=baseline_mean,
                current_density=current_density,
                deviation_score=deviation_score
            )
            
            anomalies.append(anomaly)
        
        # 检测异常空旷
        if current_density < baseline_mean * 0.1 and baseline_mean > 1.0:
            anomaly = DensityAnomaly(
                anomaly_id=str(uuid4()),
                camera_id=current_measurement.camera_id,
                zone_id=current_measurement.zone_id,
                timestamp=current_measurement.timestamp,
                anomaly_type="empty",
                severity=AlertLevel.LOW,
                description=f"检测到异常空旷：当前{current_density:.2f}，基线{baseline_mean:.2f}",
                baseline_density=baseline_mean,
                current_density=current_density,
                deviation_score=deviation_score
            )
            
            anomalies.append(anomaly)
        
        return anomalies


class CrowdDensityAnalysisService:
    """人流密度分析服务"""
    
    def __init__(self):
        self.zones: Dict[str, Zone] = {}
        self.measurements: Dict[str, deque] = defaultdict(lambda: deque(maxlen=1000))
        self.trends: Dict[str, List[DensityTrend]] = defaultdict(list)
        self.anomalies: Dict[str, List[DensityAnomaly]] = defaultdict(list)
        
        self.heatmap_generator = HeatmapGenerator()
        self.trend_analyzer = TrendAnalyzer()
        self.anomaly_detector = AnomalyDetector()
        
        # 服务状态
        self._running = False
        self._analysis_task = None
        self.analysis_interval = 60.0  # 1分钟分析一次
        
        # 初始化默认区域
        self._initialize_default_zones()
    
    def _initialize_default_zones(self):
        """初始化默认区域"""
        # 入口区域
        entrance_zone = Zone(
            zone_id="entrance",
            zone_name="入口区域",
            coordinates=[(0, 0), (200, 0), (200, 150), (0, 150)],
            max_capacity=20,
            warning_threshold=0.6,
            critical_threshold=0.8
        )
        self.zones[entrance_zone.zone_id] = entrance_zone
        
        # 中央区域
        central_zone = Zone(
            zone_id="central",
            zone_name="中央区域",
            coordinates=[(200, 150), (600, 150), (600, 450), (200, 450)],
            max_capacity=50,
            warning_threshold=0.7,
            critical_threshold=0.9
        )
        self.zones[central_zone.zone_id] = central_zone
        
        # 出口区域
        exit_zone = Zone(
            zone_id="exit",
            zone_name="出口区域",
            coordinates=[(600, 450), (800, 450), (800, 600), (600, 600)],
            max_capacity=15,
            warning_threshold=0.6,
            critical_threshold=0.8
        )
        self.zones[exit_zone.zone_id] = exit_zone
    
    async def start_analysis(self):
        """启动分析服务"""
        if self._running:
            return
        
        self._running = True
        self._analysis_task = asyncio.create_task(self._analysis_loop())
        logger.info("Crowd density analysis service started")
    
    async def stop_analysis(self):
        """停止分析服务"""
        self._running = False
        if self._analysis_task:
            self._analysis_task.cancel()
            try:
                await self._analysis_task
            except asyncio.CancelledError:
                pass
        logger.info("Crowd density analysis service stopped")
    
    async def _analysis_loop(self):
        """分析循环"""
        while self._running:
            try:
                await self._perform_periodic_analysis()
                await asyncio.sleep(self.analysis_interval)
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error(f"Error in analysis loop: {e}")
                await asyncio.sleep(10.0)
    
    async def _perform_periodic_analysis(self):
        """执行周期性分析"""
        current_time = datetime.now()
        
        for camera_id, measurements in self.measurements.items():
            if not measurements:
                continue
            
            # 趋势分析
            recent_measurements = [
                m for m in measurements 
                if (current_time - m.timestamp).total_seconds() <= 3600  # 最近1小时
            ]
            
            if len(recent_measurements) >= 10:
                trend = self.trend_analyzer.analyze_trend(recent_measurements)
                if trend:
                    self.trends[camera_id].append(trend)
                    
                    # 保持最近100个趋势
                    if len(self.trends[camera_id]) > 100:
                        self.trends[camera_id] = self.trends[camera_id][-100:]
            
            # 异常检测
            if measurements:
                latest_measurement = measurements[-1]
                historical = list(measurements)[:-1]
                
                anomalies = self.anomaly_detector.detect_anomalies(
                    latest_measurement, historical
                )
                
                if anomalies:
                    self.anomalies[camera_id].extend(anomalies)
                    
                    # 保持最近200个异常
                    if len(self.anomalies[camera_id]) > 200:
                        self.anomalies[camera_id] = self.anomalies[camera_id][-200:]
    
    async def analyze_density(
        self, 
        detection_result: PersonDetectionResult,
        image_size: Tuple[int, int],
        zones: Optional[List[str]] = None
    ) -> DensityMeasurement:
        """分析人流密度"""
        try:
            # 转换检测结果为PersonInfo格式
            persons = []
            for person_data in detection_result.persons:
                bbox_data = person_data.get("bbox", [0, 0, 100, 100])
                
                person = type('PersonInfo', (), {
                    'bbox': type('BBox', (), {
                        'x1': bbox_data[0],
                        'y1': bbox_data[1],
                        'x2': bbox_data[2],
                        'y2': bbox_data[3]
                    })()
                })()
                
                persons.append(person)
            
            # 计算整体密度
            total_area = image_size[0] * image_size[1]
            person_count = len(persons)
            
            # 估算人员占用面积
            total_person_area = sum(
                (person.bbox.x2 - person.bbox.x1) * (person.bbox.y2 - person.bbox.y1)
                for person in persons
            )
            
            density_value = total_person_area / total_area if total_area > 0 else 0
            
            # 确定密度级别
            density_level = self._classify_density_level(density_value, person_count)
            
            # 计算区域覆盖率
            area_coverage = total_person_area / total_area if total_area > 0 else 0
            
            # 计算平均人员大小
            average_person_size = total_person_area / person_count if person_count > 0 else 0
            
            # 生成热力图
            selected_zones = []
            if zones:
                selected_zones = [self.zones[zone_id] for zone_id in zones if zone_id in self.zones]
            else:
                selected_zones = list(self.zones.values())
            
            heatmap_data = self.heatmap_generator.generate_heatmap(
                persons, image_size, selected_zones
            )
            
            # 创建密度测量结果
            measurement = DensityMeasurement(
                measurement_id=str(uuid4()),
                camera_id=detection_result.camera_id,
                zone_id=None,  # 整体区域
                timestamp=detection_result.timestamp,
                person_count=person_count,
                density_value=density_value,
                density_level=density_level,
                area_coverage=area_coverage,
                average_person_size=average_person_size,
                hotspots=heatmap_data['hotspots'],
                metadata={
                    'heatmap': heatmap_data,
                    'zone_statistics': heatmap_data['zone_statistics'],
                    'image_size': image_size
                }
            )
            
            # 存储测量结果
            self.measurements[detection_result.camera_id].append(measurement)
            
            # 实时异常检测
            if len(self.measurements[detection_result.camera_id]) > 1:
                historical = list(self.measurements[detection_result.camera_id])[:-1]
                anomalies = self.anomaly_detector.detect_anomalies(measurement, historical)
                
                if anomalies:
                    self.anomalies[detection_result.camera_id].extend(anomalies)
            
            return measurement
            
        except Exception as e:
            logger.error(f"Density analysis failed: {e}")
            raise
    
    def _classify_density_level(self, density_value: float, person_count: int) -> DensityLevel:
        """分类密度级别"""
        if person_count == 0:
            return DensityLevel.LOW
        elif person_count >= 20 or density_value >= 0.3:
            return DensityLevel.CRITICAL
        elif person_count >= 10 or density_value >= 0.2:
            return DensityLevel.HIGH
        elif person_count >= 5 or density_value >= 0.1:
            return DensityLevel.MEDIUM
        else:
            return DensityLevel.LOW
    
    def add_zone(self, zone: Zone):
        """添加区域"""
        self.zones[zone.zone_id] = zone
        logger.info(f"Added zone: {zone.zone_id}")
    
    def remove_zone(self, zone_id: str) -> bool:
        """移除区域"""
        if zone_id in self.zones:
            del self.zones[zone_id]
            logger.info(f"Removed zone: {zone_id}")
            return True
        return False
    
    def get_zones(self) -> List[Zone]:
        """获取所有区域"""
        return list(self.zones.values())
    
    def get_zone(self, zone_id: str) -> Optional[Zone]:
        """获取指定区域"""
        return self.zones.get(zone_id)
    
    async def get_density_measurements(
        self,
        camera_id: str,
        zone_id: Optional[str] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        limit: int = 100
    ) -> List[DensityMeasurement]:
        """获取密度测量结果"""
        measurements = list(self.measurements.get(camera_id, []))
        
        # 过滤条件
        if zone_id:
            measurements = [m for m in measurements if m.zone_id == zone_id]
        
        if start_time:
            measurements = [m for m in measurements if m.timestamp >= start_time]
        
        if end_time:
            measurements = [m for m in measurements if m.timestamp <= end_time]
        
        # 按时间倒序排列
        measurements.sort(key=lambda x: x.timestamp, reverse=True)
        
        return measurements[:limit]
    
    async def get_density_trends(
        self,
        camera_id: str,
        zone_id: Optional[str] = None,
        limit: int = 10
    ) -> List[DensityTrend]:
        """获取密度趋势"""
        trends = self.trends.get(camera_id, [])
        
        if zone_id:
            trends = [t for t in trends if t.zone_id == zone_id]
        
        # 按时间倒序排列
        trends.sort(key=lambda x: x.end_time, reverse=True)
        
        return trends[:limit]
    
    async def get_density_anomalies(
        self,
        camera_id: str,
        zone_id: Optional[str] = None,
        start_time: Optional[datetime] = None,
        end_time: Optional[datetime] = None,
        limit: int = 50
    ) -> List[DensityAnomaly]:
        """获取密度异常"""
        anomalies = self.anomalies.get(camera_id, [])
        
        # 过滤条件
        if zone_id:
            anomalies = [a for a in anomalies if a.zone_id == zone_id]
        
        if start_time:
            anomalies = [a for a in anomalies if a.timestamp >= start_time]
        
        if end_time:
            anomalies = [a for a in anomalies if a.timestamp <= end_time]
        
        # 按时间倒序排列
        anomalies.sort(key=lambda x: x.timestamp, reverse=True)
        
        return anomalies[:limit]
    
    async def generate_heatmap(
        self,
        detection_result: PersonDetectionResult,
        image_size: Tuple[int, int],
        zones: Optional[List[str]] = None
    ) -> Dict[str, Any]:
        """生成热力图"""
        # 转换检测结果
        persons = []
        for person_data in detection_result.persons:
            bbox_data = person_data.get("bbox", [0, 0, 100, 100])
            
            person = type('PersonInfo', (), {
                'bbox': type('BBox', (), {
                    'x1': bbox_data[0],
                    'y1': bbox_data[1],
                    'x2': bbox_data[2],
                    'y2': bbox_data[3]
                })()
            })()
            
            persons.append(person)
        
        # 选择区域
        selected_zones = []
        if zones:
            selected_zones = [self.zones[zone_id] for zone_id in zones if zone_id in self.zones]
        else:
            selected_zones = list(self.zones.values())
        
        return self.heatmap_generator.generate_heatmap(persons, image_size, selected_zones)
    
    async def get_statistics(
        self,
        camera_id: str,
        time_range: timedelta = timedelta(hours=1)
    ) -> Dict[str, Any]:
        """获取统计信息"""
        end_time = datetime.now()
        start_time = end_time - time_range
        
        measurements = await self.get_density_measurements(
            camera_id=camera_id,
            start_time=start_time,
            end_time=end_time,
            limit=1000
        )
        
        if not measurements:
            return {
                'camera_id': camera_id,
                'time_range': {
                    'start': start_time.isoformat(),
                    'end': end_time.isoformat()
                },
                'total_measurements': 0,
                'statistics': {}
            }
        
        # 计算统计指标
        densities = [m.density_value for m in measurements]
        person_counts = [m.person_count for m in measurements]
        
        stats = {
            'total_measurements': len(measurements),
            'density_statistics': {
                'mean': np.mean(densities),
                'median': np.median(densities),
                'std': np.std(densities),
                'min': np.min(densities),
                'max': np.max(densities)
            },
            'person_count_statistics': {
                'mean': np.mean(person_counts),
                'median': np.median(person_counts),
                'std': np.std(person_counts),
                'min': np.min(person_counts),
                'max': np.max(person_counts)
            },
            'density_level_distribution': {},
            'peak_times': [],
            'anomaly_count': len(self.anomalies.get(camera_id, []))
        }
        
        # 密度级别分布
        level_counts = defaultdict(int)
        for measurement in measurements:
            level_counts[measurement.density_level.value] += 1
        
        stats['density_level_distribution'] = dict(level_counts)
        
        # 查找峰值时间
        sorted_measurements = sorted(measurements, key=lambda x: x.person_count, reverse=True)
        stats['peak_times'] = [
            {
                'timestamp': m.timestamp.isoformat(),
                'person_count': m.person_count,
                'density_value': m.density_value
            }
            for m in sorted_measurements[:5]
        ]
        
        return {
            'camera_id': camera_id,
            'time_range': {
                'start': start_time.isoformat(),
                'end': end_time.isoformat()
            },
            'statistics': stats
        }
    
    async def process_video_frame(self, frame: np.ndarray, metadata: Dict[str, Any] = None) -> Dict[str, Any]:
        """处理视频帧进行人群密度分析"""
        try:
            camera_id = metadata.get('camera_id', 'unknown') if metadata else 'unknown'
            frame_timestamp = datetime.fromisoformat(metadata.get('frame_timestamp')) if metadata and metadata.get('frame_timestamp') else datetime.now()
            
            # 模拟人员检测结果
            mock_detection_result = self._create_mock_detection_result(frame, camera_id, frame_timestamp)
            
            # 分析密度
            image_size = (frame.shape[1], frame.shape[0])
            measurement = await self.analyze_density(mock_detection_result, image_size)
            
            # 生成热力图
            heatmap_data = await self.generate_heatmap(mock_detection_result, image_size)
            
            return {
                "algorithm": "crowd_density",
                "camera_id": camera_id,
                "frame_timestamp": frame_timestamp.isoformat(),
                "processing_timestamp": datetime.now().isoformat(),
                "results": {
                    "person_count": measurement.person_count,
                    "density_value": measurement.density_value,
                    "density_level": measurement.density_level.value,
                    "area_coverage": measurement.area_coverage,
                    "hotspots": measurement.hotspots,
                    "zone_statistics": measurement.metadata.get('zone_statistics', {}),
                    "heatmap_summary": {
                        "total_persons": heatmap_data.get('total_persons', 0),
                        "hotspot_count": len(heatmap_data.get('hotspots', [])),
                        "grid_size": heatmap_data.get('grid_size', 20)
                    }
                },
                "confidence": 0.88,
                "processing_time": 0.15
            }
            
        except Exception as e:
            logger.error(f"人群密度分析处理视频帧失败: {e}")
            return {
                "algorithm": "crowd_density",
                "camera_id": metadata.get('camera_id', 'unknown') if metadata else 'unknown',
                "error": str(e),
                "processing_timestamp": datetime.now().isoformat()
            }
    
    def _create_mock_detection_result(self, frame: np.ndarray, camera_id: str, timestamp: datetime):
        """创建模拟检测结果"""
        height, width = frame.shape[:2]
        
        # 生成随机数量的人员
        num_persons = np.random.randint(0, 15)  # 0-14个人
        persons = []
        
        for i in range(num_persons):
            # 随机生成边界框
            x1 = np.random.randint(0, width - 80)
            y1 = np.random.randint(0, height - 120)
            x2 = x1 + np.random.randint(40, 80)
            y2 = y1 + np.random.randint(80, 120)
            
            # 确保边界框在图像范围内
            x2 = min(x2, width)
            y2 = min(y2, height)
            
            person_data = {
                "person_id": f"person_{i}",
                "bbox": [x1, y1, x2, y2],
                "confidence": np.random.uniform(0.7, 0.95)
            }
            persons.append(person_data)
        
        # 创建检测结果对象
        return type('PersonDetectionResult', (), {
            'camera_id': camera_id,
            'timestamp': timestamp,
            'persons': persons,
            'total_count': len(persons)
        })()


# 全局人流密度分析服务实例
crowd_density_analysis_service = CrowdDensityAnalysisService()